home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- From: steve@caticsuf.CSUFresno.EDU (Steve Mitchell)
- Subject: v26i074: em - expire mail messages, Part01/01
- Message-ID: <1991Nov26.043002.3198@sparky.imd.sterling.com>
- X-Md4-Signature: 409399ad06396bdf23520a37e6c19558
- Date: Tue, 26 Nov 1991 04:30:02 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: steve@csufresno.edu (Steve Mitchell)
- Posting-number: Volume 26, Issue 74
- Archive-name: em/part01
- Environment: UNIX
-
- I recently needed to deal with users whose mailboxes are
- used as depositories of information that really should be
- saved in separate files. Some of the messages in mailboxes
- on our system were over 1000 days old! I didn't like
- the utility 'junkmail', so I wrote my own.
-
- Expire Mail works by scanning the mailboxes specified on the
- command line and reporting on messages that are older than the
- specified age, or deleting messages older than the specified
- age, or both.
-
- Expire Mail has been tested under SunOS 4.1 and BSD 4.3.
- It also compiles and appears to work under AT&T System V 3.1.
-
- Critiques, suggestions, questions, flames welcome.
-
- Steve Mitchell
- California State University, Fresno
- Steve_Mitchell@csufresno.edu
- ---
- |#| Steve Mitchell KD6BET |#|
- |#| California Agricultural Technology Institute +1 209 278 5675 |#|
- |#| California State University, Fresno steve@csufresno.edu |#|
- |#| Fresno, CA 93740-0115 "Now, Steve is happy." |#|
- ---
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # README
- # Makefile
- # em.1
- # em.c
- # This archive created: Mon Nov 25 09:33:06 1991
- export PATH; PATH=/bin:$PATH
- if test -f 'README'
- then
- echo shar: will not over-write existing file "'README'"
- else
- cat << \SHAR_EOF > 'README'
-
- I recently needed to deal with users whose mailboxes are
- used as depositories of information that really should be
- saved in separate files. Some of the messages in mailboxes
- on our system were over 1000 days old! I didn't like
- the utility 'junkmail', so I wrote my own.
-
- Expire Mail works by scanning the mailboxes specified on the
- command line and reporting on messages that are older than the
- specified age, or deleting messages older than the specified
- age, or both.
-
- Expire Mail has been tested under SunOS 4.1 and BSD 4.3.
- It also compiles and appears to work under AT&T System V 3.1.
-
- Critiques, suggestions, questions, flames welcome.
-
- Steve Mitchell
- California State University, Fresno
- Steve_Mitchell@csufresno.edu
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'Makefile'
- then
- echo shar: will not over-write existing file "'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- # Good for System V
- #CFLAGS= -O -DUTIME
-
- # Good for BSD
- CFLAGS= -O
-
- em: em.c
- cc ${CFLAGS} -o em em.c
-
- install: em em.1
- install em /usr/local/bin
- install em.1 /usr/local/man/man1
-
- shar: README Makefile em.1 em.c
- shar README Makefile em.1 em.c > em.shar
-
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'em.1'
- then
- echo shar: will not over-write existing file "'em.1'"
- else
- cat << \SHAR_EOF > 'em.1'
- .TH EM L "18 November 1991"
- .SH NAME
- em \- expire mail messages
- .SH SYNOPSIS
- .B em
- [
- .B \-dovz
- ] [
- .B -a
- .I age
- ] [
- .B -u
- .I username
- ]
- .I mailbox
- \&.\|.\|.
- .SH DESCRIPTION
- .LP
- .B em
- scans mailboxes for expired messages (messages older than
- .I age
- days) and deletes them. Messages newer than the expiration age
- are left in the mailbox.
- .SH OPTIONS
- .TP
- .B \-a age
- specify how many days old an expired message is. Default is 180
- (six months).
- .TP
- .B \-d
- Debug. Only generate an audit trail, no actual message deletion
- takes place.
- .TP
- .B \-o
- Do not remove a mailbox just because the file's modification time
- is older than
- .I age
- days. Instead, explicitly scan the mailbox to ensure that all
- messages have expired.
- .TP
- .B \-u username
- Specify that only messages from
- .I username
- will be considered for expiration. Useful for removing all messages
- sent from an offensive user.
- .TP
- .B \-v
- Be verbose. In addition to normal message expiration, debug information
- is printed as well.
- .TP
- .B \-z
- Do not remove mailboxes of zero length. The default is for
- .B em
- to remove all mailbox files that are empty.
- .SH EXAMPLES
- To remove all messages older than 60 days from all mailboxes:
- .LP
- .RS
- .nf
- .ft B
- example% em -a 60 /usr/spool/mail/*
- .ft R
- .fi
- .RE
- .br
- .ne 10
- .LP
- .SH AUTHOR
- Steve Mitchell (steve_mitchell@csufresno.edu)
- .SH WARNINGS
- .LP
- Always try
- .B em
- using the 'd' option before letting it loose on your
- system's mailboxes.
- .SH BUGS
- mailbox locking could be done better.
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'em.c'
- then
- echo shar: will not over-write existing file "'em.c'"
- else
- cat << \SHAR_EOF > 'em.c'
- /*
- ** em: expire mail messages
- **
- **
- ** Options:
- **
- ** -a age
- ** Specify how many days old an 'expired' message is. Default
- ** is 180 (six months).
- ** -d
- ** Debug. Only generates an audit trail. No actual removal takes
- ** place. More 'd's, more debugging information.
- ** -o
- ** Do not remove mailboxes just because they're older than 'age'
- ** days. Instead, explicitly scan the mailbox to ensure that all
- ** messages have expired. The default is for em to remove any
- ** mailboxes that have modification times older than 'age' days.
- ** -u username
- ** Secify that only messages from 'username' will be considered
- ** for expiration. Useful for removing messages from an offensive
- ** user.
- ** -v
- ** Be verbose. This option produces the same output as the debug
- ** option but all actions are followed through. That is, messages
- ** are expired, mailboxes are removed, etc.
- ** -z
- ** Do not remove mailboxes of zero length.
- **
- **
- ** Author:
- **
- ** Steve Mitchell
- ** California State University, Fresno
- ** steve_mitchell@csufresno.edu
- **
- **
- ** NOTICE:
- **
- ** THE AUTHOR OFFERS NO WARRANTY FOR THE PERFORMANCE OF THIS SOFTWARE.
- ** (In other words, use at your own risk)
- **
- **
- ** Version History:
- **
- ** 09/12/91: first version
- **
- */
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <ctype.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <fcntl.h>
- #ifdef UTIME
- #ifdef sun
- #include <utime.h>
- #endif
- #endif
-
- #ifndef S_ISREG
- #define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
- #endif
-
- int aged = 160;
- int sec_aged;
- int debug = 0;
- int verbose = 0;
- int oldflag = 1;
- int zeroflag = 1;
- char *fromwho = (char *)0;
- char *myname;
- char *whoami;
- time_t currtime;
- #ifdef UTIME
- struct utimbuf tv;
- #else
- struct timeval tv[2];
- #endif
- int mbox_id;
-
- void usage();
- time_t time();
- char *getlogin();
- char *strrchr();
-
- time_t mystrptime();
- void resettimes();
-
- struct msg {
- char *from;
- time_t time;
- };
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
- FILE *mfp;
- FILE *ofp;
- char *mailbox;
- int c;
- int errflg = 0;
- int num_expired = 0;
- extern char *optarg;
- extern int optind;
- struct stat sbuf;
- char tname[BUFSIZ];
- char *p;
-
- myname = argv[0];
-
- whoami = getlogin();
-
- while((c = getopt(argc,argv,"a:dou:vz")) != -1)
- switch(c) {
- case 'a':
- aged = atoi(optarg);
- break;
- case 'd':
- debug++;
- break;
- case 'o':
- oldflag = 0;
- break;
- case 'u':
- fromwho = optarg;
- break;
- case 'v':
- verbose = 1;
- break;
- case 'z':
- zeroflag = 0;
- break;
- default:
- errflg++;
- }
-
- if(errflg || optind == argc) {
- usage();
- return(1);
- }
-
- sec_aged = aged * 86400;
-
- (void)time(&currtime);
-
- for(;optind < argc; optind++) {
- mailbox = argv[optind];
-
- if(stat(mailbox,&sbuf) < 0) {
- perror(mailbox);
- continue;
- }
- #ifdef UTIME
- tv.actime = sbuf.st_atime;
- tv.modtime = sbuf.st_mtime;
- #else
- tv[0].tv_sec = sbuf.st_atime;
- tv[1].tv_sec = sbuf.st_mtime;
- #endif
-
- mbox_id = sbuf.st_uid;
-
- p = strrchr(mailbox,'.');
- if(p)
- if(!strcmp(p,".lock"))
- continue;
-
- if(locked(mailbox)) {
- (void)fprintf(stderr,"%s: locked\n",mailbox);
- continue;
- }
- #ifdef S_ISREG
- if(!S_ISREG(sbuf.st_mode)) {
- (void)fprintf(stderr,"%s: not a regular file\n",
- mailbox);
- continue;
- }
- #endif
- if(debug >= 1 || verbose >= 1)
- (void)printf("%s:\n",mailbox);
- if(currtime - sbuf.st_mtime > sec_aged && oldflag) {
- if(debug >= 1 || verbose >= 1)
- (void)printf(
- "\tolder than %d days - remove\n",aged);
- if(!debug)
- if(unlink(mailbox) < 0)
- perror(mailbox);
- continue;
- }
- if(sbuf.st_size == 0 && zeroflag) {
- if(debug >= 1 || verbose >= 1)
- (void)printf("\tzero length - remove\n");
- if(!debug)
- if(unlink(mailbox) < 0)
- perror(mailbox);
- continue;
- }
- if(!lock(mailbox)) {
- (void)fprintf(stderr,"%s: can't lock\n",mailbox);
- continue;
- }
- if((mfp = fopen(mailbox,"r")) == NULL) {
- perror(mailbox);
- continue;
- }
-
- p = strrchr(mailbox,'/');
- if(p)
- p++;
- else
- p = mailbox;
- (void)sprintf(tname,"/tmp/%s.expire",p);
-
- if((ofp = fopen(tname,"w")) == NULL) {
- perror(tname);
- (void)fclose(mfp);
- resettimes(mailbox);
- (void)unlock(mailbox);
- continue;
- }
-
- num_expired = do_msgs(mfp,ofp);
-
- if(stat(tname,&sbuf) < 0) {
- perror(tname);
- (void)unlock(mailbox);
- continue;
- }
- if(sbuf.st_size == 0 && zeroflag) {
- if(debug >= 1 || verbose >= 1) {
- (void)printf("\tzero length - remove\n");
- resettimes(mailbox);
- }
- if(!debug)
- if(unlink(mailbox) < 0)
- perror(mailbox);
- if(unlink(tname) < 0)
- perror(tname);
- (void)unlock(mailbox);
- continue;
- }
- if(debug || !num_expired) {
- (void)unlink(tname);
- (void)fclose(mfp);
- resettimes(mailbox);
- if(!unlock(mailbox))
- (void)fprintf(stderr,
- "%s: can't unlock\n",mailbox);
- continue;
- }
-
- if((mfp = fopen(mailbox,"w")) == NULL) {
- perror(mailbox);
- (void)unlock(mailbox);
- continue;
- }
- if((ofp = fopen(tname,"r")) == NULL) {
- perror(tname);
- (void)fclose(mfp);
- resettimes(mailbox);
- (void)unlock(mailbox);
- continue;
- }
- while((c = fgetc(ofp)) != EOF)
- (void)fputc(c,mfp);
- (void)fclose(ofp);
- (void)fclose(mfp);
-
- resettimes(mailbox);
-
- if(!unlock(mailbox)) {
- (void)fprintf(stderr,"%s: can't unlock\n",mailbox);
- continue;
- }
-
- if(unlink(tname) < 0)
- perror(tname);
- }
- return(0);
- }
-
-
- void
- resettimes(mbox)
- char *mbox;
- {
- if(geteuid() == 0 || getuid() == mbox_id ) {
- #ifdef UTIME
- if(utime(mbox,&tv) < 0) {
- perror("utime");
- }
- #else
- tv[0].tv_usec = (time_t)0;
- tv[1].tv_usec = (time_t)0;
- if(utimes(mbox,tv) < 0) {
- perror("utimes");
- }
- #endif
- }
- }
-
- do_msgs(mfp,ofp)
- FILE *mfp;
- FILE *ofp;
- {
- int writeout = 1;
- int msgnum = 0;
- char buf[BUFSIZ];
- struct msg msg;
- int num_expired = 0;
-
-
- while(fgets(buf,BUFSIZ,mfp)) {
- if(!strncmp("From ",buf,5)) {
- msgnum++;
- get_msg_info(buf,&msg);
- if(msg.time < 0) {
- (void)fprintf(stderr,"Bad header\n");
- continue;
- }
- if(debug >= 3 || verbose >= 3)
- (void)printf("\t\tmessage from %s %d\n",
- msg.from, msg.time);
- if(currtime - msg.time > sec_aged) {
- writeout = 0;
- num_expired++;
- if(fromwho && strcmp(fromwho,msg.from))
- writeout = 1;
- if((debug >= 1 || verbose >= 1) && !writeout)
- (void)printf(
- "\tmessage #%d, expired (%d days)\n",
- msgnum,(currtime-msg.time)/86400);
- if(debug >= 2 || verbose >= 2)
- (void)printf(
- "\t\tcurrtime = %d, msg.time = %d\n",
- currtime,msg.time);
- if(debug >= 2 || verbose >= 2)
- (void)printf("\t\tfrom = %s\n", msg.from);
- } else {
- writeout = 1;
- }
- }
- if(writeout)
- (void)fprintf(ofp,"%s",buf);
- }
- (void)fclose(mfp);
- (void)fclose(ofp);
- return(num_expired);
- }
-
-
- get_msg_info(fromp,s)
- char *fromp;
- struct msg *s;
- {
- static char name[1024];
- char *p, *wp;
- #ifdef HAVE_STRPTIME
- struct tm tm;
- #endif
-
- for(p=fromp;*p!=' ';p++)
- ;
- for(;*p==' ';p++)
- ;
- for(wp=name;*p!=' ';p++,wp++)
- *wp = *p;
- *wp = 0;
- s->from = name;
-
-
- for(;*p==' ';p++)
- ;
-
- #ifdef HAVE_STRPTIME
- strptime(p,"%a %h %e %H:%M:%S %Y",&tm);
- s->time = timelocal(&tm);
- #else
- s->time = mystrptime(p);
- #endif /* HAVE_STRPTIME */
- if(debug >= 3) {
- (void)printf("\t\ttimelocal = %ld\n",s->time);
- }
- }
-
- #define equal(S1,S2) (!strcmp(S1,S2))
-
- #define MINUTE (60L)
- #define HOUR (MINUTE * 60L)
- #define DAY (HOUR * 24L)
- #define RYEAR (DAY * 365L)
- #define LYEAR (DAY * 366L)
-
- struct mons {
- int days;
- char *month;
- } months[] = {
- 31, "Jan",
- 28, "Feb",
- 31, "Mar",
- 30, "Apr",
- 31, "May",
- 30, "Jun",
- 31, "Jul",
- 31, "Aug",
- 30, "Sep",
- 31, "Oct",
- 30, "Nov",
- 31, "Dec",
- 0, 0
- };
-
- time_t
- mystrptime(s)
- char *s;
- {
- struct mons *mp;
- char mymon[4];
- char myyear[5];
- char *p;
- int dom, tot=0, year, mfound=0;
- int hr, min;
- int dindex = 70;
- long sectot=0;
-
- if(sscanf(s,"%*s %s %d %d:%d",
- mymon,&dom,&hr,&min) < 3) {
- (void)fprintf(stderr,"Bad date format\n");
- return(-1);
- }
-
- p = s + strlen(s);
- for(;!isdigit(*p);p--)
- ;
- p-=3;
- (void)strncpy(myyear,p,4);
- myyear[4] = 0;
-
- year = atoi(myyear);
-
- /* handle leap years */
- if((year % 4) == 0)
- months[1].days++;
-
- /* add to tot until we find the month we're looking for */
- for(mp=months;mp->days;mp++) {
- if(equal(mp->month,mymon)) {
- mfound++;
- break;
- }
- tot += mp->days;
- }
-
- if(!mfound) {
- (void)fprintf(stderr,"Bad date format\n");
- return(-1);
- }
-
- sectot = ((tot+dom-1)*DAY) + (hr*HOUR) + (min*MINUTE);
-
- for(dindex=70;dindex<(year-1900);dindex++)
- if(dindex % 4 == 0)
- sectot += LYEAR;
- else
- sectot += RYEAR;
-
- return(sectot);
- }
-
- locked(file)
- char *file;
- {
- char lfile[BUFSIZ];
- struct stat sbuf;
- int count = 0;
-
- (void)sprintf(lfile,"%s.lock",file);
-
- for(count = 0; count < 3; count++) {
- if(stat(lfile,&sbuf) < 0)
- break;
- else
- sleep(3);
- }
- return(count==3);
- }
-
- lock(file)
- char *file;
- {
- char fname[BUFSIZ];
- int fd;
-
- (void)sprintf(fname,"%s.lock",file);
-
- if((fd = open(fname,O_CREAT,0700)) < 0) {
- perror(fname);
- return(0);
- }
- (void)close(fd);
- return(1);
- }
-
- unlock(file)
- char *file;
- {
- char fname[BUFSIZ];
-
- (void)sprintf(fname,"%s.lock",file);
-
- if(unlink(fname) < 0) {
- perror(fname);
- return(0);
- }
- return(1);
- }
-
- void
- usage()
- {
- (void)fprintf(stderr,
- "Usage: %s [-a age] [-d] [-o] [-u username] [-v] [-z] mailbox..\n",
- myname);
- }
- SHAR_EOF
- fi # end of overwriting check
- # End of shell archive
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-